# -*- coding: utf-8 -*-
"""配置管理模块

提供系统配置管理功能，包括默认模型路径、检测参数、设备设置等
"""

import logging
import os
import json
from pathlib import Path
from typing import Any, Optional, Dict, List

logger = logging.getLogger(__name__)

# 内存缓存配置，避免频繁查询数据库
_config_cache = {}

# 默认配置
default_configs = {
    # 系统基本配置
    'system.name': 'YOLO智能交通监控系统',
    'system.version': '1.0.0',
    'system.build_date': 'unknown',
    'system.build_number': '0',
    'system.log_level': 'INFO',
    'system.log_file': './logs/yolo_apply.log',
    'system.temp_dir': './temp/',
    'system.cache_dir': './cache/',
    'system.enable_backup': True,
    'system.backup_dir': './backups/',
    
    # API配置
    'api.version': 'v1',
    'api.port': 5000,
    'api.host': '127.0.0.1',
    'api.jwt.secret': os.environ.get('JWT_SECRET', 'default_secret_key'),
    'api.jwt.algorithm': 'HS256',
    'api.jwt.expires_in': 3600,
    'api.debug': False,
    'api.enable_cors': True,
    
    # 数据库配置
    'database.type': 'sqlite',
    'database.sqlite.path': './data/yolo_apply.db',
    'database.postgres.host': 'localhost',
    'database.postgres.port': 5432,
    'database.postgres.database': 'yolo_apply',
    'database.postgres.user': 'admin',
    'database.postgres.password': 'password',
    'database.mysql.host': 'localhost',
    'database.mysql.port': 3306,
    'database.mysql.database': 'yolo_apply',
    'database.mysql.user': 'admin',
    'database.mysql.password': 'password',
    'database.echo': False,
    'database.pool_size': 10,
    'database.max_overflow': 20,
    'database.log_file': './logs/database.log',
    
    # 模型配置
    'models.default_path': './models/',
    'models.supported_extensions': ['.pt', '.onnx'],
    'models.cache_enabled': True,
    'models.cache_dir': './cache/models/',
    
    # 检测基础配置
    'detection.model_path': './models/yolov8n.pt',
    'detection.confidence_threshold': 0.5,
    'detection.iou_threshold': 0.45,
    'detection.nms_threshold': 0.45,
    'detection.device': 'auto',
    'detection.device_priority': ['cuda', 'cpu'],
    'detection.classes': [0, 1, 2, 3, 5, 7],
    'detection.input_size': (640, 640),
    'detection.use_letterbox': True,
    'detection.max_detections': 100,
    
    # 检测模式配置
    'detection.modes.traffic.target_classes': ['car', 'truck', 'bus', 'motorcycle', 'bicycle'],
    'detection.modes.traffic.confidence_threshold': 0.6,
    'detection.modes.helmet.target_classes': ['person', 'helmet', 'no_helmet'],
    'detection.modes.helmet.confidence_threshold': 0.65,
    'detection.modes.face.target_classes': ['face'],
    'detection.modes.face.confidence_threshold': 0.7,
    'detection.modes.general.target_classes': [],
    'detection.modes.general.confidence_threshold': 0.5,
    
    # 跟踪配置
    'tracking.iou_threshold': 0.3,
    'tracking.track_buffer': 30,
    'tracking.max_track_age': 30,
    'tracking.max_distance': 30,
    'tracking.use_kalman_filter': True,
    'tracking.show_tracks': True,
    'tracking.track_color': (255, 100, 50),
    
    # 结果处理配置
    'result_processing.filter_min_confidence': 0.5,
    'result_processing.filter_min_area': 500,
    'result_processing.apply_nms': True,
    'result_processing.nms_threshold': 0.45,
    'result_processing.apply_class_filter': False,
    'result_processing.allowed_classes': [],
    'result_processing.min_aspect_ratio': 0.1,
    'result_processing.max_aspect_ratio': 10.0,
    
    # 可视化配置
    'visualization.show_confidence': True,
    'visualization.show_class': True,
    'visualization.show_tracking': True,
    'visualization.show_tracking_id': True,
    'visualization.show_statistics': True,
    'visualization.font_scale': 0.5,
    'visualization.line_thickness': 2,
    'visualization.box_opacity': 0.8,
    
    # 帧处理配置
    'frame_processing.resize.width': 0,
    'frame_processing.resize.height': 0,
    'frame_processing.resize.maintain_aspect_ratio': True,
    'frame_processing.resize.letterboxing': False,
    'frame_processing.enhancement.brightness': 0.0,
    'frame_processing.enhancement.contrast': 1.0,
    'frame_processing.enhancement.saturation': 1.0,
    'frame_processing.enhancement.sharpness': 0.0,
    'frame_processing.display.show_fps': True,
    'frame_processing.display.show_timestamp': True,
    'frame_processing.display.show_camera_info': True,
    
    # 性能优化配置
    'performance.enable_profiling': False,
    'performance.enable_optimization': True,
    'performance.max_batch_size': 8,
    'performance.dynamic_input_size': True,
    'performance.automatic_batch': False,
    'performance.precision': 'float32',
    
    # 数据配置
    'data.classes': ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 
                    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 
                    'stop sign', 'parking meter', 'bench', 'bird', 'cat', 
                    'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 
                    'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 
                    'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 
                    'sports ball', 'kite', 'baseball bat', 'baseball glove', 
                    'skateboard', 'surfboard', 'tennis racket', 'bottle', 
                    'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 
                    'banana', 'apple', 'sandwich', 'orange', 'broccoli', 
                    'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 
                    'couch', 'potted plant', 'bed', 'dining table', 'toilet', 
                    'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 
                    'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 
                    'book', 'clock', 'vase', 'scissors', 'teddy bear', 
                    'hair drier', 'toothbrush'],
    
    # 默认模型配置
    'default_models': json.dumps([
        {
            'engine_id': 'yolov8_default',
            'engine_type': 'yolo',
            'model_path': './models/yolov8n.pt',
            'device': 'auto',
            'kwargs': {
                'confidence_threshold': 0.5,
                'nms_threshold': 0.45,
                'max_detections': 100
            }
        },
        {
            'engine_id': 'tracking_default',
            'engine_type': 'yolo_tracking',
            'model_path': './models/yolov8n.pt',
            'device': 'auto',
            'kwargs': {
                'confidence_threshold': 0.5,
                'nms_threshold': 0.45,
                'tracking_iou_threshold': 0.3,
                'track_buffer': 30,
                'max_track_age': 30
            }
        }
    ])
}

def get_config(key: str, default: Any = None) -> Any:
    """获取配置值
    
    首先尝试从缓存中获取配置，如果缓存中不存在，则尝试从环境变量获取，
    如果环境变量中也不存在，则返回默认配置或提供的默认值。
    注意：这里不直接从数据库获取配置以避免循环依赖，数据库服务会调用此函数。
    
    Args:
        key: 配置键，支持点表示法访问嵌套配置
        default: 如果配置不存在，返回的默认值
        
    Returns:
        配置值
    """
    # 首先检查缓存
    if key in _config_cache:
        return _config_cache[key]
    
    # 尝试从环境变量获取（将点转换为下划线，大写）
    env_key = key.replace('.', '_').upper()
    if env_key in os.environ:
        value = os.environ[env_key]
        # 缓存结果
        _config_cache[key] = value
        return value
    
    # 检查默认配置
    if key in default_configs:
        value = default_configs[key]
        # 缓存结果
        _config_cache[key] = value
        return value
    
    # 返回提供的默认值
    return default

def set_config(key: str, value: Any) -> None:
    """设置配置值
    
    设置配置值到缓存和数据库
    
    Args:
        key: 配置键
        value: 配置值
    """
    # 更新缓存
    _config_cache[key] = value
    
    # 更新数据库
    try:
        from database import db_service
        db_service.set_config(key, value)
    except (ImportError, Exception) as e:
        logger.error(f"更新数据库配置失败: {str(e)}")

def clear_config_cache() -> None:
    """清除配置缓存"""
    global _config_cache
    _config_cache.clear()
    logger.info("配置缓存已清除")

def get_config_section(section: str) -> Dict[str, Any]:
    """获取配置部分
    
    获取以特定前缀开头的所有配置
    
    Args:
        section: 配置部分前缀
        
    Returns:
        配置字典
    """
    section_dict = {}
    
    # 从默认配置中获取
    for key, value in default_configs.items():
        if key.startswith(f"{section}."):
            section_key = key[len(section) + 1:]
            section_dict[section_key] = value
    
    # 从环境变量获取
    env_prefix = section.replace('.', '_').upper() + '_'
    for key in os.environ:
        if key.startswith(env_prefix):
            section_key = key[len(env_prefix):].lower()
            section_dict[section_key] = os.environ[key]
    
    # 从缓存中获取
    for key, value in _config_cache.items():
        if key.startswith(f"{section}."):
            section_key = key[len(section) + 1:]
            section_dict[section_key] = value
    
    return section_dict

def get_all_configs() -> Dict[str, Any]:
    """获取所有配置
    
    Returns:
        所有配置的字典
    """
    all_configs = {}
    
    # 添加默认配置
    all_configs.update(default_configs)
    
    # 添加环境变量配置
    for key in os.environ:
        config_key = key.lower().replace('_', '.')
        all_configs[config_key] = os.environ[key]
    
    # 添加缓存配置
    all_configs.update(_config_cache)
    
    return all_configs

def get_model_config(model_id: str) -> Dict[str, Any]:
    """获取模型配置
    
    Args:
        model_id: 模型ID
        
    Returns:
        Dict: 模型配置
    """
    try:
        # 获取默认模型配置列表
        default_models_str = get_config('default_models')
        default_models = json.loads(default_models_str) if isinstance(default_models_str, str) else default_models_str
        
        # 查找匹配的模型配置
        for model_config in default_models:
            if model_config.get('engine_id') == model_id:
                return model_config
    except Exception as e:
        logger.error(f"解析默认模型配置失败: {e}")
    
    # 返回默认配置
    return {
        'engine_id': model_id,
        'engine_type': 'yolo',
        'device': get_config('detection.device', 'auto'),
        'kwargs': {
            'confidence_threshold': get_config('detection.confidence_threshold', 0.5),
            'nms_threshold': get_config('detection.nms_threshold', 0.45)
        }
    }

def get_mode_config(mode: str) -> Dict[str, Any]:
    """获取检测模式配置
    
    Args:
        mode: 检测模式名称
        
    Returns:
        Dict: 模式配置
    """
    # 获取模式配置
    target_classes = get_config(f'detection.modes.{mode}.target_classes', [])
    confidence_threshold = get_config(f'detection.modes.{mode}.confidence_threshold', 0.5)
    
    # 如果模式不存在特定配置，尝试使用通用模式配置
    if target_classes is [] and confidence_threshold == 0.5:
        target_classes = get_config('detection.modes.general.target_classes', [])
        confidence_threshold = get_config('detection.modes.general.confidence_threshold', 0.5)
    
    return {
        'target_classes': target_classes,
        'confidence_threshold': confidence_threshold
    }

def get_device_priority() -> List[str]:
    """获取设备优先级列表
    
    Returns:
        List[str]: 设备优先级列表
    """
    return get_config('detection.device_priority', ['cuda', 'cpu'])

def init_logging():
    """初始化日志配置"""
    try:
        # 获取日志配置
        log_file = get_config('system.log_file', './logs/yolo_apply.log')
        log_level = get_config('system.log_level', 'INFO')
        
        # 创建日志目录
        log_dir = os.path.dirname(log_file)
        if log_dir:
            Path(log_dir).mkdir(parents=True, exist_ok=True)
        
        # 设置日志级别
        level = getattr(logging, log_level.upper(), logging.INFO)
        
        # 配置根日志记录器
        logging.basicConfig(
            level=level,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file, encoding='utf-8'),
                logging.StreamHandler()
            ]
        )
        
        logger.info(f"日志配置初始化完成，日志级别: {log_level}")
        
    except Exception as e:
        # 如果日志配置失败，使用默认配置
        logging.basicConfig(level=logging.INFO)
        logging.error(f"日志配置初始化失败: {e}")

def ensure_directories():
    """确保配置中的目录存在"""
    # 获取需要创建的目录列表
    directories = [
        get_config('system.temp_dir', './temp/'),
        get_config('system.cache_dir', './cache/'),
        get_config('system.backup_dir', './backups/'),
        get_config('models.default_path', './models/'),
        get_config('models.cache_dir', './cache/models/'),
        os.path.dirname(get_config('system.log_file', './logs/yolo_apply.log'))
    ]
    
    # 创建目录
    for directory in directories:
        if directory:
            try:
                Path(directory).mkdir(parents=True, exist_ok=True)
            except Exception as e:
                logger.error(f"创建目录失败 {directory}: {e}")